﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Ivory.Libs
{
    public class Config
    {
        //Fields
        private Dictionary<string, object> _FlagValues;
        public object this[string flagName]
        {
            get { return _FlagValues.Where(p => p.Key == flagName).SingleOrDefault(); }
            set { ModifyValue(flagName, value); }
        }
           
		private string  _FileLocation; 
		public string FileLocation
		{
			get { return _FileLocation; }
			set { _FileLocation = value; }
		} 
		
        //Construct
        public Config()
        {
            _FlagValues = new Dictionary<string, object>();
        }
        public Config(string file)
        {
            _FlagValues = new Dictionary<string, object>();
            LoadConfigFile(file);
            _FileLocation = file;
        }

        //Methods
        private bool ParseableAsInt(string s, out int i)
        {
            //Attempts to parse s into T            
            return int.TryParse(s, out i);
        }
        private bool ParseableAsBoolean(string s, out bool b)
        {
            //Attempts to parse s into T            
            return bool.TryParse(s, out b);
        }

        public void ModifyValue(string flagName, object value)
        {
            //TODO:
        }

        public bool LoadConfigFile(string file)
        {
            int lineNum = 0;
            try
            {
                using (StreamReader configReader = new StreamReader(file))
                {
                    string line;

                    while ((line = configReader.ReadLine()) != null)
                    {
                        if (line.StartsWith("[")) //Escape char used for grouping for easier reading, we ignore [Graphics] etc.
                            continue;
                        else if (line.StartsWith("**"))
                            continue; // Comment dont pass

                        string flag = "";
                        object value = null;

                        //width=1024
                        string[] split = line.Split('=');
                        flag = split[0];

                        if (_FlagValues.ContainsKey(flag))
                            throw new IvoryFrameworkError(Errors.FlagRecognisedException(flag));
                        
                        //The value, first try to parse as a number, then as a boolean, if all fails leave as string
                        int h = 0;
                        bool b = false;
                        if (ParseableAsInt(split[1], out h))
                            value = h;
                        else if (ParseableAsBoolean(split[1], out b))
                            value = b;
                        else
                            value = split[1];

                        _FlagValues.Add(flag, value);
                        lineNum++;
                    }
                }
            }
            catch (FileNotFoundException) {
                throw new IvoryFrameworkError(Errors.ConfigLoadException(file));
            }
            catch (IndexOutOfRangeException) {
                throw new IvoryFrameworkError(Errors.ConfigReadException(file, lineNum));
            }
            
            //return
            return true;
        }
        public void SaveConfigFile()
        {
            using (StreamWriter writer = new StreamWriter(FileLocation))
            {
                foreach(KeyValuePair<string, object> pair in _FlagValues)
                {
                    string name = pair.Key;
                    object oData = pair.Value;

                    writer.WriteLine(name + "=" + oData);
                }
            };
        }

        public T GetValueByFlag<T>(string flag)
        {
            if (!_FlagValues.ContainsKey(flag))
                throw new IvoryFrameworkError(Errors.ConfigRequestException(flag));                

            return (T)_FlagValues[flag];
        }
        public void EditFlagValue<T>(string flag, T value)
        {
            if(!_FlagValues.ContainsKey(flag))
                throw new IvoryFrameworkError(Errors.ConfigRequestException(flag));

            _FlagValues[flag] = value;
        }
    }
}
